/**
 * Copyright (c) 2022 Beijing Jiaotong University
 * PhotLab is licensed under [Open Source License].
 * You can use this software according to the terms and conditions of the [Open Source License].
 * You may obtain a copy of [Open Source License] at: [https://open.source.license/]
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *
 * See the [Open Source License] for more details.
 *
 * Author: Zhenjie Wei
 * Created: Oct. 24, 2023
 * Supported by: National Key Research and Development Program of China
 */

import { Direction } from '@/common/logic/common/types2D'
import { IComparable } from '@/common/logic/common/types'
import { uid_rt } from '@/common/logic/common/uid'
import { RenderPort as PhotPort } from '@/common/types/phot_types'

export enum PortType {
    IN = 0,
    OUT = 1,
}

export enum PortAspect {
    LEFT = 0,
    RIGHT = 1,
    TOP = 2,
    BOTTOM = 3,
}

export default class RenderPort implements IComparable {
    public id: number
    // port location, indicate the logical bias of the port
    // from the top-left point of the element node
    public loc: number
    // port type, in or out
    public typ: PortType
    // which aspect is the port located at
    public asp: PortAspect
    public connected = false

    public get dir() {
        if (this.typ === PortType.OUT) {
            switch (this.asp) {
                case PortAspect.LEFT:
                    return Direction.LEFT
                case PortAspect.RIGHT:
                    return Direction.RIGHT
                case PortAspect.TOP:
                    return Direction.UP
                case PortAspect.BOTTOM:
                    return Direction.DOWN
            }
        } else {
            switch (this.asp) {
                case PortAspect.LEFT:
                    return Direction.RIGHT
                case PortAspect.RIGHT:
                    return Direction.LEFT
                case PortAspect.TOP:
                    return Direction.DOWN
                case PortAspect.BOTTOM:
                    return Direction.UP
            }
        }
    }

    constructor(loc: number, typ: PortType, asp: PortAspect, id: number) {
        this.loc = loc
        this.typ = typ
        this.asp = asp
        this.id = id
    }

    equals(other: RenderPort) {
        return (
            this.typ === other.typ &&
            this.loc === other.loc &&
            this.asp === other.asp
        )
    }

    static fromObject(obj: PhotPort) {
        if (
            !obj ||
            obj.location == null ||
            obj.direction == null ||
            obj.aspect == null ||
            obj.portId == null
        ) {
            throw new Error('Invalid port object.')
        }
        return new RenderPort(
            obj.location ?? 0,
            (obj.direction ?? PortType.IN) as unknown as PortType,
            (obj.aspect ?? PortAspect.LEFT) as PortAspect,
            Number(obj.portId) ?? 0
        )
    }
}
